package com.nd.fastdp.security.controller;

import com.nd.fastdp.framework.pojo.constant.BaseEnum;
import com.nd.fastdp.framework.pojo.constant.RespCodeEnum;
import com.nd.fastdp.framework.pojo.vo.Result;
import com.nd.fastdp.utils.HttpServletRequestUtil;
import com.nd.fastdp.utils.HttpServletResponseUtil;
import com.nd.fastdp.utils.RequestDetail;
import com.nd.fastdp.utils.RequestDetailThreadLocal;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @description 对异常进行返回处理
 */
//@ControllerAdvice
@Slf4j
public class SecurityExceptionController {

    /**
     * 登录授权异常处理
     *
     * @param exception
     * @return
     */
    @ExceptionHandler(value = {AuthenticationException.class})
    @ResponseStatus(HttpStatus.OK)
    public Object authenticationExceptionHandler(AuthenticationException exception, HttpServletRequest request, HttpServletResponse response) {

        printRequestDetail();
        log.debug("[AuthenticationException] message={}", exception);

        if(HttpServletRequestUtil.isAjax()){
            HttpServletResponseUtil.printJson(response, Result.FAILD(RespCodeEnum.UNAUTHORIZED.getValue(), exception.getMessage()));
        }

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error/401");

        return modelAndView;
    }

    @ExceptionHandler(value = {UnauthenticatedException.class})
    @ResponseStatus(HttpStatus.OK)
    public Object unauthenticatedExceptionHandler(UnauthenticatedException exception, HttpServletRequest request, HttpServletResponse response) {

        printRequestDetail();
        log.debug("[UnauthenticatedException] message={}", exception);

        if(HttpServletRequestUtil.isAjax()){
            HttpServletResponseUtil.printJson(response, Result.FAILD(RespCodeEnum.UNAUTHORIZED.getValue(), exception.getMessage()));
        }

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error/401");

        return modelAndView;
    }

    /**
     * 未授权异常处理
     *
     * @param exception
     * @return
     */
    @ExceptionHandler(value = UnauthorizedException.class)
    @ResponseStatus(HttpStatus.OK)
    public Object unauthorizedExceptionHandler(UnauthorizedException exception, HttpServletRequest request, HttpServletResponse response) {

        printRequestDetail();
        log.debug("[UnauthorizedException] message={}", exception);

        if(HttpServletRequestUtil.isAjax()){
            HttpServletResponseUtil.printJson(response, Result.FAILD(RespCodeEnum.NOT_PERMISSION));
        }

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error/403");

        return modelAndView;
    }

    /*****************
     * 以下异常已放置到JwtFilter中，待后续优化
     */
    /*@ExceptionHandler(value = TokenNotEmptyException.class)
    @ResponseStatus(HttpStatus.OK)
    public Object tokenNotEmptyExceptionHandler(TokenNotEmptyException exception, HttpServletRequest request, HttpServletResponse response) {

        printRequestDetail();
        log.debug("[TokenNotEmptyException] message={}", exception);


        if(HttpServletRequestUtil.isAjax()){
            return Result.FAILD(RespCodeEnum.UNAUTHORIZED);
        }

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("errorMsg", exception.getMessage());
        modelAndView.setViewName("error/403");

        return modelAndView;
    }

    @ExceptionHandler(value = TokenExpiredException.class)
    @ResponseStatus(HttpStatus.OK)
    public Object tokenExpiredExceptionHandler(TokenExpiredException exception, HttpServletRequest request, HttpServletResponse response) {

        printRequestDetail();
        log.debug("[TokenExpiredException] message={}", exception);


        if(HttpServletRequestUtil.isAjax()){
            return Result.FAILD(RespCodeEnum.UNAUTHORIZED);
        }

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("errorMsg", exception.getMessage());
        modelAndView.setViewName("error/403");

        return modelAndView;
    }


    *//**
     * JWT Token解析异常
     *
     * @param exception
     * @return
     *//*
    @ExceptionHandler(value = JWTVerificationException.class)
    @ResponseStatus(HttpStatus.OK)
    public Object jWTVerificationExceptionHandler(JWTVerificationException exception, HttpServletRequest request, HttpServletResponse response) {

        printRequestDetail();
        log.debug("[JWTVerificationException] message={}", exception);


        if(HttpServletRequestUtil.isAjax()){
            return Result.FAILD(RespCodeEnum.UNAUTHORIZED);
        }

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error/403");

        return modelAndView;
    }*/

    /**
     * 打印请求详情
     */
    private void printRequestDetail() {

        RequestDetail requestDetail = RequestDetailThreadLocal.getRequestDetail();
        if (requestDetail != null) {
            log.error("异常来源：ip: {}, path: {}", requestDetail.getIp(), requestDetail.getPath());
        }
    }

    /**
     * 获取ApiCode格式化字符串
     *
     * @param apiCode
     * @return
     */
    private String getApiCodeString(BaseEnum apiCode) {
        if (apiCode != null) {
            return String.format("errorCode: %s, errorMessage: %s", apiCode.getValue(), apiCode.getDesc());
        }
        return null;
    }

    /**
     * 打印错误码及异常
     *
     * @param apiCode
     * @param exception
     */
    private void printApiCodeException(BaseEnum apiCode, Exception exception) {
        log.error(getApiCodeString(apiCode), exception);
    }

}

